<template>
  <div>
    <!-- 面包屑导航 -->
    <el-header>
      <el-breadcrumb separator-class="el-icon-arrow-right">
        <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
        <el-breadcrumb-item>权限管理</el-breadcrumb-item>
        <el-breadcrumb-item>角色列表</el-breadcrumb-item>
      </el-breadcrumb>
    </el-header>
    <!-- 主体部分 -->
    <el-card>
      <!-- 添加角色按钮 -->
      <el-button type="primary" @click="addRoleForm.visible = true">添加角色</el-button>

      <!-- 展示角色的表格 -->
      <el-table :data="totalRoles" border stripe>
        <!-- 展开行的按钮 -->
        <el-table-column type="expand">
          <template slot-scope="scope">
            <!-- 自定义递归组件 用于在展开行区域显示所有权限树 -->
            <tag-tree :total-rights="totalRights" :id="scope.row.id"
                      :rights="scope.row.rights" @tag_close="tagClose"></tag-tree>
          </template>
        </el-table-column>
        <!-- 索引列 -->
        <el-table-column type="index" label="#"></el-table-column>
        <!-- 角色名列 -->
        <el-table-column prop="name" label="角色名"></el-table-column>
        <!-- 角色描述列 -->
        <el-table-column prop="direction" label="角色描述"></el-table-column>
        <!-- 操作列 -->
        <el-table-column label="操作" width="230px">
          <template slot-scope="scope">
            <!-- 修改按钮 -->
            <el-button type="primary" @click="setRoleClick(scope.row,scope.$index)"
                       icon="el-icon-edit" size="mini"></el-button>
            <!-- 删除按钮 -->
            <el-button type="danger" icon="el-icon-delete" size="mini"
                       @click="delRoleClick(scope.row.id,scope.$index)"></el-button>
            <!-- 分配权限按钮 -->
            <el-button type="warning" icon="el-icon-setting"
                       @click="showCheckDialog(scope.row)" size="mini">分配权限
            </el-button>
          </template>
        </el-table-column>
      </el-table>
    </el-card>

    <!-- 添加角色弹出框 -->
    <el-dialog title="分配权限" :visible.sync="addRoleForm.visible"
               width="30%" @close="$refs.addRoleForm.resetFields()">
      <!-- 添加角色表单 -->
      <el-form :model="addRoleForm.data" :rules="addRoleForm.rules"
               ref="addRoleForm" label-width="100px">
        <el-form-item label="角色名:" prop="name">
          <el-input v-model="addRoleForm.data.name"></el-input>
        </el-form-item>
        <el-form-item label="角色描述:" prop="direction">
          <el-input v-model="addRoleForm.data.direction"></el-input>
        </el-form-item>
      </el-form>
      <span slot="footer">
        <el-button @click="addRoleForm.visible = false">取 消</el-button>
        <el-button type="primary" @click="addRoleSubmit">确 定</el-button>
      </span>
    </el-dialog>

    <!-- 修改角色弹出框 -->
    <el-dialog title="分配权限" :visible.sync="setRoleForm.visible" width="30%">
      <!-- 添加角色表单 -->
      <el-form :model="setRoleForm.data" :rules="setRoleForm.rules"
               ref="setRoleForm" label-width="100px">
        <el-form-item label="角色名:" prop="name">
          <el-input v-model="setRoleForm.data.name"></el-input>
        </el-form-item>
        <el-form-item label="角色描述:" prop="direction">
          <el-input v-model="setRoleForm.data.direction"></el-input>
        </el-form-item>
      </el-form>
      <span slot="footer">
        <el-button @click="setRoleForm.visible = false">取 消</el-button>
        <el-button type="primary" @click="setRoleSubmit">确 定</el-button>
      </span>
    </el-dialog>

    <!-- 分配权限弹出框 -->
    <el-dialog title="分配权限" :visible.sync="setRightsVisible"
               class="dialog" width="30%">
      <!-- 权限列表树结构el-tree -->
      <!-- 究极巨坑，必须在显示el-tree之前先修改checkRights 否则显示出来的还是原来的 -->
      <!-- 这里添加v-if="setRightsVisible" 在修改setRightsVisible之前先修改checkRights -->
      <div style="min-height: 130px">
        <el-tree :props="{label: 'authName',children: 'children'}"
                 v-if="setRightsVisible"
                 :data="totalRights" show-checkbox node-key="id"
                 :default-checked-keys="checkRights" ref="dialogTree">
        </el-tree>
      </div>
      <span slot="footer">
        <el-button @click="setRightsVisible = false">取 消</el-button>
        <el-button type="primary" @click="submitRights">确 定</el-button>
      </span>
    </el-dialog>
  </div>
</template>

<script>
// 自定义组件TagTree 用于做组件递归
import TagTree from '@/components/TagTree'

export default {
  name: 'Roles',
  components: { TagTree },
  comments: [TagTree],
  data() {
    return {
      // 存放所有权限，tree形式
      totalRights: [],
      // 存放所有角色列表
      totalRoles: [],
      // 控制分配权限弹出框是否显示
      setRightsVisible: false,
      // 分配权限弹出框 默认选中的选项
      checkRights: [],
      // 分配权限弹出框 当前id
      roleId: 0,
      // 添加角色表单
      addRoleForm: {
        data: {
          name: '',
          direction: ''
        },
        rules: {
          name: [
            { required: true, message: '角色名不能为空！', trigger: 'blur' },
            { max: 10, message: '不能超过10个字符', trigger: 'blur' }
          ],
          direction: [{ max: 20, message: '不能超过20个字符', trigger: 'blur' }]
        },
        visible: false
      },
      setRoleForm: {
        data: {
          id: 0,
          name: '',
          direction: ''
        },
        // 当前数据所在数组的索引
        index: -1,
        // form表单项的规则，与addRoleForm中的相同，在created中赋值
        rules: {},
        visible: false
      }
    }
  },
  methods: {
    // 获取所有权限列表
    async getTotalRights() {
      let { data: res } = await this.$ajax.get('rights/tree/')
      if (res.status === 'success') {
        this.totalRights = res.data
        this.$message.success('获取权限列表成功')
      } else
        this.$message.error('获取权限列表失败')
    },
    // 获取所有角色列表
    async getTotalRoles() {
      let { data: res } = await this.$ajax.get('roles/')
      if (res.status === 'success') {
        this.totalRoles = res.data
        this.$message.success('获取角色列表成功')
      } else
        this.$message.error('获取角色列表失败')
    },
    // 提交选中项
    async submitRights() {
      let dialogTree = this.$refs.dialogTree
      // 完全选中列表
      let checkedKeys = dialogTree.getCheckedKeys()
      // 半选中列表
      let halfCheckedKeys = dialogTree.getHalfCheckedKeys()
      // 包含所有完全选中和半选中的列表
      let list = [...checkedKeys, ...halfCheckedKeys]
      let { data: res } = await this.$ajax.post(`roles/${this.roleId}`,
              { rights: list })
      if (res === 'OK') {
        this.$message.success('设置权限成功')
        // 如果修改权限成功，则重置本地数据
        for (let item of this.totalRoles)
          if (item.id === this.roleId) {
            item.rights = list
            item.rights_no_half = checkedKeys
            break
          }
        this.setRightsVisible = false
      } else
        this.$message.error('设置权限失败')
    },
    // 显示分配权限弹出框
    showCheckDialog(roleInfo) {
      this.checkRights = roleInfo.rights_no_half
      this.roleId = roleInfo.id
      // 究极巨坑 这一行必须放在最下面
      // 要在显示el-tree组件之前修改checkRights，否则修改无效
      this.setRightsVisible = true
    },
    // 角色权限树中点击关闭按钮时调用
    // id是role_id,rid是right_id
    async tagClose(id, rid) {
      this.$confirm('此操作将永久删除该权限, 是否继续?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(async () => {
        let { data: res } = await this.$ajax.put(`roles/${id}/${rid}/`)
        if (res.status === 'success') {
          this.$message.success('删除权限成功！')
          // 如果删除权限成功，则重置本地内容
          for (let item of this.totalRoles)
            if (item.id === id) {
              item.rights = res.data.rights
              item.rights_no_half = res.data.rights_no_half
              break
            }
        } else
          this.$message.success('删除权限失败！')
      })
    },
    // 添加角色表单提交
    addRoleSubmit() {
      this.$refs.addRoleForm.validate(async valid => {
        if (!valid) return
        let { data: res } = await this.$ajax.post('add_role/',
                this.$ajax.stringify(this.addRoleForm.data))
        if (res.status === 'success') {
          this.totalRoles.push(res.data[0])
          this.addRoleForm.visible = false
          this.$message.success('添加角色成功')
        } else
          this.$message.error('添加角色失败')
      })
    },
    // 修改角色表单提交
    async setRoleSubmit() {
      let { data: res } = await this.$ajax.post('set_role/',
              this.$ajax.stringify(this.setRoleForm.data))
      if (res.status === 'success') {
        this.totalRoles.splice(this.setRoleForm.index, 1, res.data[0])
        this.setRoleForm.visible = false
        this.$message.success('修改角色信息成功')
      } else
        this.$message.error('修改角色信息失败')
    },
    // 修改角色按钮点击事件
    setRoleClick(row, index) {
      let form = this.setRoleForm.data
      // 显示输入框
      this.setRoleForm.visible = true
      // 等待组件渲染完毕后赋值
      this.$nextTick(() => {
        this.setRoleForm.index = index
        form.id = row.id
        form.name = row.name
        form.direction = row.direction
      })
    },
    // 删除角色按钮点击事件
    delRoleClick(id, index) {
      this.$confirm('此操作将永久删除该角色, 是否继续?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(async () => {
        let { data: res } = await this.$ajax.post('del_role/',
                this.$ajax.stringify({ id }))
        if (res.status === 'OK') {
          this.totalRoles.splice(index, 1)
          this.$message.success('删除角色成功')
        } else
          this.$message.error('删除角色失败')
      })
    }
  },
  created() {
    this.getTotalRoles()
    this.getTotalRights()
    // 规则复用
    this.setRoleForm.rules = this.addRoleForm.rules
  }
}
</script>

<style lang="less" scoped>
.el-header {
  display: flex;
  align-items: center;
}

.el-table {
  margin-top: 15px;
}

.dialog > .el-dialog__body {
  min-height: 320px;
}
</style>